package com.liwc.shiro;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.gson.Gson;
import com.liwc.model.SysMenu;
import com.liwc.model.SysRole;
import com.liwc.model.SysUser;
import com.liwc.service.MenuService;
import com.liwc.service.UserService;
import com.liwc.util.WebHelper;

public class ShiroDBRealm extends AuthorizingRealm {

	private static final Logger logger = org.slf4j.LoggerFactory.getLogger(ShiroDBRealm.class);
	
	
	
	@Autowired
	private UserService userService;

	@Autowired
	private MenuService resourceService;

	/**
	 * 授权
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

		String userName = (String) principals.getPrimaryPrincipal();
		SysUser user = userService.findUserByName(userName);
		
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		Set<SysRole> roleSet = user.getRoles();

		Set<String> permissionSet = new HashSet<String>();
		for (SysRole role : roleSet) {
			if (StringUtils.isNotBlank(role.getRoleName())) {
				info.addRole(role.getRoleName());
				
				Set<SysMenu> resources = role.getMenus();
				if (resources != null && !resources.isEmpty()) {
					for (SysMenu r : resources) {
						if (StringUtils.isNotBlank(r.getMenuUrl())) {
							permissionSet.add(r.getMenuUrl());
						}
					}
				}
			}
		}

		info.addStringPermissions(permissionSet);

		return info;
	}

	/**
	 * 验证当前用户
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) {

		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;

		if (StringUtils.isEmpty(token.getUsername())) {
			return null;
		}

		SysUser user = userService.findUserByName(token.getUsername());
		if (user != null) {

			if (user.getUserStatus() == SysUser.STATUS_NO) {
				throw new LockedAccountException();
			}

			AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUserLoginId(), user.getUserPasswd(),
					getName());

			setSession(WebHelper.SESSION_LOGIN_USER, user);

			initMenu(user.getId());

			return authcInfo;
		}

		return null;
	}

	
	
	private void initMenu(Integer userId) {

		// 菜单权限
		List<SysMenu> menuResources = resourceService.findAllWithChild();

		List<SysMenu> hasResource = new ArrayList<SysMenu>();

		Map<String, String> map = userService.findResourceMap(userId);

		if (menuResources != null && !menuResources.isEmpty()) {
			for (SysMenu resource : menuResources) {
				SysMenu retRes = hasResource(resource, map);
				if (retRes != null) {
					hasResource.add(retRes);
				}
			}
		}

		Gson gson = new Gson();
		
		logger.debug("----->权限菜单："+ gson.toJson(hasResource));
		
		setSession(WebHelper.SESSION_MENU_RESOURCE, hasResource);

	}

	private SysMenu hasResource(SysMenu resource, Map<String, String> map) {
		
		if (map.containsKey(String.valueOf(resource.getId()))) {
			List<SysMenu> chResources = resource.getChildren();
			List<SysMenu> hasChResources = new ArrayList<SysMenu>();
			if (chResources != null && !chResources.isEmpty()) {
				for (SysMenu chRes : chResources) {
					SysMenu retRes = hasResource(chRes, map);
					if (retRes != null) {
						hasChResources.add(retRes);
					}
				}
			}
			resource.setChildren(hasChResources);
			return resource;
		} else {
			return null;
		}
	}

	/**
	 * 
	 * @param key
	 * @param value
	 */
	private void setSession(Object key, Object value) {
		Subject subject = SecurityUtils.getSubject();
		if (subject != null) {
			Session session = subject.getSession();
			if (session != null) {
				session.setAttribute(key, value);
			}
		}
	}

}
